﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IWshRuntimeLibrary;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.DirectoryServices;
using System.IO;

namespace PSE.Deployment.Util
{
    public class Windows
    {
        [DllImport("shell32.dll")]
        private static extern bool SHGetSpecialFolderPath(IntPtr hwndOwner, [Out] StringBuilder lpszPath, int nFolder, bool fCreate);

        public enum SpecialFolder
        {
            Desktop = 0x0019,
            StartMenu = 0x0017,
            ApplicationData = 0x0023
        }

        public static bool CheckVersionWithIIS7Compatibility()
        {
            return (System.Environment.OSVersion.Platform == System.PlatformID.Win32NT && System.Environment.OSVersion.Version.Major >= 6);
        }

        public static bool CheckVersion()
        {
            bool isSupportedWindowsVersion = false;

            System.OperatingSystem osInfo = System.Environment.OSVersion;

            switch (osInfo.Platform)
            {
                case System.PlatformID.Win32NT:

                    switch (osInfo.Version.Major)
                    {
                        case 5:
                            //Windows XP / 2003
                            if (osInfo.Version.Minor == 1)
                            {
                                if ((!String.IsNullOrEmpty(osInfo.ServicePack)) && (!osInfo.ServicePack.ToUpper().Contains("SERVICE PACK 1")))
                                    isSupportedWindowsVersion = true;
                            }
                            else if (osInfo.Version.Minor == 2)
                                isSupportedWindowsVersion = true;
                            break;
                        case 6:
                            isSupportedWindowsVersion = true;
                            break;
                        case 7:
                            isSupportedWindowsVersion = true;
                            break;
                        case 8:
                            isSupportedWindowsVersion = true;
                            break;
                    }

                    break;
            }

            return isSupportedWindowsVersion;
        }

        public static void CreateShortcut(string pathLink, string iconLocation, string targetPath)
        {
            CreateShortcut(pathLink, iconLocation, targetPath, string.Empty);
        }

        public static void CreateShortcut(string pathLink, string iconLocation, string targetPath, string arguments)
        {
            IWshShortcut link;
            WshShell shell = new WshShell();
            
            link = (IWshShortcut)shell.CreateShortcut(pathLink);

            if (!string.IsNullOrEmpty(iconLocation))
            {
                link.IconLocation = iconLocation;
                link.Arguments = arguments;
            }
            
            link.TargetPath = targetPath;
            
            link.Save();
        }

        public static string GetFolderPath(SpecialFolder specialFolder)
        {
            StringBuilder path = new StringBuilder(260);

            SHGetSpecialFolderPath(IntPtr.Zero, path, (int)specialFolder, true);

            return path.ToString();
        }

        /// <summary>
        /// Instalar um pacote Msi
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static int InstallMsiPackage(string fileName, bool quietMode, bool passiveMode)
        {
            Process p = new Process();
            p.StartInfo.FileName = "msiexec.exe";
            p.StartInfo.Arguments = string.Format("/i \"{0}\" {1} {2}", fileName, quietMode ? "/qn" : "", passiveMode ? "/passive" : "");
            p.Start();

            p.WaitForExit();

            return p.ExitCode;
        }

        /// <summary>
        /// Desinstalar um pacote Msi
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static int UninstallMsiPackage(string fileName, bool quietMode, bool passiveMode)
        {
            Process p = new Process();
            p.StartInfo.FileName = "msiexec.exe";
            p.StartInfo.Arguments = string.Format("/x \"{0}\" {1} {2}", fileName, quietMode ? "/qn" : "", passiveMode ? "/passive" : "");
            p.Start();

            p.WaitForExit();

            return p.ExitCode;
        }

        /// <summary>
        /// Executar um processo aguardando o término da execução
        /// </summary>
        /// <param name="fileName">arquivo a ser executado</param>
        /// <param name="arguments">argumentos de execução</param>
        /// <returns></returns>
        public static int RunProcess(string fileName, string arguments)
        {
            return RunProcess(fileName, arguments, null, null, 0);
        }

        public static int RunProcess(string fileName)
        {
            return RunProcess(fileName, null, null, null, 0);
        }

        public static int RunProcess(string fileName, string arguments, int timeOut)
        {
            return RunProcess(fileName, arguments, null, null, timeOut);
        }

        /// <summary>
        /// Executar um processo aguardando o término da execução
        /// </summary>
        /// <param name="fileName">arquivo a ser executado</param>
        /// <param name="arguments">argumentos de execução</param>
        /// <param name="timeOut">Tempo máximo quer irá aguardar a execução (ms)</param>
        public static int RunProcess(string fileName, string arguments, DataReceivedEventHandler errorDataReceived, DataReceivedEventHandler outputDataReceived, int timeOut)
        {
            System.Diagnostics.Process p = new System.Diagnostics.Process();
            p.StartInfo.FileName = fileName;
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.RedirectStandardOutput = true;

            if (!string.IsNullOrEmpty(arguments))
                p.StartInfo.Arguments = arguments;

            if (errorDataReceived != null)
                p.ErrorDataReceived += errorDataReceived;

            if (outputDataReceived != null)
                p.OutputDataReceived += outputDataReceived;

            p.Start();

            p.BeginOutputReadLine();
            p.BeginErrorReadLine();

            if (timeOut > 0)
                p.WaitForExit(timeOut);
            else
                p.WaitForExit();

            return p.ExitCode;
        }

        /// <summary>
        /// Para o processo imediatamente
        /// </summary>
        /// <param name="processName">Nome do processo</param>
        /// <returns></returns>
        public static int KillProcess(string processName)
        {
            return RunProcess("cmd.exe", string.Format("/c taskkill /F /IM \"{0}.exe\"", processName));
        }

        /// <summary>
        /// Cria um grupo do Active Directory no computador local
        /// </summary>
        /// <param name="groupName">Nome do grupo</param>
        /// <param name="description">Descrição do grupo</param>
        public static void CreateLocalGroup(string groupName, string description)
        {
            DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName + ", Computer");
            DirectoryEntry group = localMachine.Children.Add(groupName, "group");
            group.Properties["Description"].Add(description);
            group.CommitChanges();
        }

        /// <summary>
        /// Remove grupo do Active Directory no computador local
        /// </summary>
        /// <param name="groupName">Nome do grupo</param>
        public static void RemoveLocalGroup(string groupName)
        {
            DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName + ", Computer");
            DirectoryEntry group = localMachine.Children.Add(groupName, "group");
            localMachine.Children.Remove(group);

        }

        /// <summary>
        /// Verifica se o grupo do Active Directory existe no computador local
        /// </summary>
        /// <param name="groupName">Nome do grupo</param>
        /// <returns></returns>
        public static bool ExistsLocalGroup(string groupName)
        {
            bool exists = true;

            try
            {
                DirectoryEntry localMachine = new DirectoryEntry("WinNT://" + Environment.MachineName + ", Computer");
                localMachine.Children.Find(groupName, "group");
            }
            catch (COMException ex)
            {
                if (ex.ErrorCode == -2147022676)
                    exists = false;
                else
                    throw;
            }

            return exists;
        }

        /// <summary>
        /// Verificar o caminho source de instalação é válido checando pela existência do 
        /// arquivo 'SetupConfiguration.xml' e a pasra 'Bin' no diretório informado.
        /// Não é realizada uma verificação arquivo a arquivo pois seria inviável.
        /// </summary>
        /// <param name="path">caminho de origem de instalação</param>
        /// <returns></returns>
        public static bool CheckInstallationSource(string path)
        {
            return System.IO.File.Exists(Path.Combine(path, "SetupConfiguration.xml")) && System.IO.Directory.Exists(Path.Combine(path, "Bin"));
        }
    }
}
